package com.ruleengine.context.impl;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import org.apache.log4j.Logger;

import com.ruleengine.context.EContextPropertyScope;
import com.ruleengine.context.EContextPropertyType;
import com.ruleengine.context.ExecuteResult;
import com.ruleengine.context.IContextProperty;
import com.ruleengine.context.IWorkflowConext;
import com.ruleengine.instruction.Instruction;
import com.ruleengine.instruction.InstructionSet;

/**
 * @author AB033862 Jul 26, 2012
 */
public class WorkflowContext implements IWorkflowConext {
    private static Logger logger = Logger.getLogger(WorkflowContext.class);
    private InstructionSet instructions = null;
    private Object data;
    private String workflowId;
    private String executeId;
    private Map<String, IContextProperty<?>> localParams = new HashMap<String, IContextProperty<?>>();
    private int pcCount;
    private Exception cause;

    public String getExecuteId() {
        // TODO Auto-generated method stub
        return executeId;
    }

    public void setExecuteId(String executeId) {
        // TODO Auto-generated method stub
        this.executeId = executeId;
    }

    public void addPcCount(int pcCount) {
        // TODO Auto-generated method stub
        this.pcCount += pcCount;
    }

    public int getPcCount() {
        // TODO Auto-generated method stub
        return pcCount;
    }

    public void setPcCount(int pcCount) {
        // TODO Auto-generated method stub
        this.pcCount = pcCount;
    }

    public WorkflowContext() {
    }

    public WorkflowContext(String workflowId) {
        this.workflowId = workflowId;
    }

    public String getWorkflowId() {
        return workflowId;
    }

    public Object getWorkflowData() {
        // TODO Auto-generated method stub
        return data;
    }

    public void setWorkflowData(Object e) {
        // TODO Auto-generated method stub
        data = e;
    }

    public InstructionSet getInstructionSet() {
        // TODO Auto-generated method stub
        return instructions;
    }

    void setInstructionSet(InstructionSet instructions) {
        // TODO Auto-generated method stub
        this.instructions = instructions;
    }

    public Instruction getCurrentInstruction() {
        // TODO Auto-generated method stub
        return instructions.getInstruction(this.pcCount);
    }

    public ExecuteResult getExecuteResult() {
        // TODO Auto-generated method stub
        return null;
    }

    public void setExecuteResult(ExecuteResult result) {
        // TODO Auto-generated method stub

    }

    /*
     * (non-Javadoc)
     * 
     * @see com.wx.workflow.engine.context.IWorkflowConext#getContextProperty(java.lang.String)
     */
    public <T> IContextProperty<T> getContextProperty(String key) {
        // TODO Auto-generated method stub
        IContextProperty p = this.localParams.get(key);
        return p;
    }

    public <T> IContextProperty<T> removeContextProperty(String key) {
        // TODO Auto-generated method stub
        IContextProperty p = this.localParams.remove(key);
        return p;
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.wx.workflow.engine.context.IWorkflowConext#setContextProperty(com.wx.workflow.engine.context.IContextProperty)
     */
    public <T> void setContextProperty(IContextProperty<T> property) {
        if (localParams.get(property.getKey()) != null) {
            throw new RuntimeException("the property is already exsit");
        }
        localParams.put(property.getKey(), property);
    }

    public Iterator<IContextProperty<?>> propertyIterator() {
        // TODO Auto-generated method stub
        return localParams.values().iterator();
    }

    public boolean isBack() {
        // TODO Auto-generated method stub
        return false;
    }

    public Exception getExceptionCause() {
        // TODO Auto-generated method stub
        return cause;
    }

    public void setExceptionCause(Exception cause) {
        // TODO Auto-generated method stub
        this.cause = cause;
    }

    @Override
    public Object clone() throws CloneNotSupportedException {
        // TODO Auto-generated method stub
        WorkflowContext c = (WorkflowContext) super.clone();
        return c;
    }

    public void combination(IWorkflowConext context) {
        // TODO Auto-generated method stub
        this.cause = context.getExceptionCause();
        Iterator<IContextProperty<?>> it = context.propertyIterator();
        while (it.hasNext()) {
            IContextProperty<?> p = it.next();
            if (p.getScope() != EContextPropertyScope.PUBLIC) {
                if (logger.isDebugEnabled()) {
                    logger.debug("[" + p.getKey()
                            + "] is a private property, ignore it");
                }
                continue;
            }
            // 合并public属性
            IContextProperty ori = localParams.get(p.getKey());
            if (ori == null) {
                // 新增属性
                localParams.put(p.getKey(), p);
            } else if (p.equals(ori)) {
                // 同一个属性
                if (p.getType() == EContextPropertyType.VARIABLE) {
                    // 变量,合并属性值
                    if (logger.isDebugEnabled()) {
                        logger.debug("change property [" + p.getKey()
                                + "] from [" + ori.getValue() + "] to ["
                                + p.getValue() + "]");
                    }
                    ori.setValue(p.getValue());
                } else {
                    if (logger.isDebugEnabled()) {
                        logger.debug("[" + p.getKey()
                                + "] is a constant property, ignore it");
                    }
                }

            } else {
                throw new RuntimeException(
                        "the property named ["
                                + p.getKey()
                                + "] is already in context, but the inner properties is not consistency");
            }
        }
    }

}
